#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2025/5/11 16:00
# @Author  : Chenmm
# @File    : base.py
# @Software: PyCharm
# @Des: 基础模型

from tortoise import fields
from tortoise.models import Model
from datetime import datetime
import re
from typing import Optional, Union


'''自定义创建时间和更新时间字段'''
class CreateTimeField(fields.DatetimeField):
    """创建时间字段 (自动设置初始时间)"""

    def __init__(self, **kwargs):
        # 禁用自动更新，启用自动添加
        kwargs['auto_now'] = False
        kwargs['auto_now_add'] = True
        super().__init__(**kwargs)

    def to_db_value(
            self,
            value: Optional[datetime],
            instance: Union[Model, None]
    ) -> Optional[str]:
        """将datetime转换为字符串格式"""
        if value is None:
            return None
        return value.strftime("%Y-%m-%d %H:%M:%S")

    def to_python_value(
            self,
            value: Union[datetime, str, None]
    ) -> Optional[str]:
        """转换为格式化字符串"""
        if value is None:
            return None

        if isinstance(value, datetime):
            return value.strftime("%Y-%m-%d %H:%M:%S")

        if isinstance(value, str):
            # 验证格式
            if re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$", value):
                return value
            try:
                # 尝试解析ISO格式
                dt = datetime.fromisoformat(value)
                return dt.strftime("%Y-%m-%d %H:%M:%S")
            except (ValueError, TypeError):
                pass

        return str(value)

    def pre_save(
            self,
            model_instance: Model,
            name: str
    ) -> Union[datetime, str]:
        """确保新记录设置创建时间"""
        value = getattr(model_instance, name)

        # 如果是新记录且值为空，设置当前时间
        if not model_instance._saved_in_db and value is None:
            value = datetime.now()
            setattr(model_instance, name, value)

        return value


class UpdateTimeField(fields.DatetimeField):
    """更新时间字段 (每次保存自动更新)"""

    def __init__(self, **kwargs):
        # 启用自动更新，禁用自动添加
        kwargs['auto_now'] = True
        kwargs['auto_now_add'] = False
        super().__init__(**kwargs)

    def to_db_value(
            self,
            value: Optional[datetime],
            instance: Union[Model, None]
    ) -> Optional[str]:
        """将datetime转换为字符串格式"""
        if value is None:
            return None
        return value.strftime("%Y-%m-%d %H:%M:%S")

    def to_python_value(
            self,
            value: Union[datetime, str, None]
    ) -> Optional[str]:
        """转换为格式化字符串"""
        if value is None:
            return None

        if isinstance(value, datetime):
            return value.strftime("%Y-%m-%d %H:%M:%S")

        if isinstance(value, str):
            # 验证格式
            if re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$", value):
                return value
            try:
                # 尝试解析ISO格式
                dt = datetime.fromisoformat(value)
                return dt.strftime("%Y-%m-%d %H:%M:%S")
            except (ValueError, TypeError):
                pass

        return str(value)

    def pre_save(
            self,
            model_instance: Model,
            name: str
    ) -> Union[datetime, str]:
        """每次保存时更新为当前时间"""
        # 总是设置为当前时间
        value = datetime.now()
        setattr(model_instance, name, value)
        return value


class TimestampMixin(Model):
    create_time = CreateTimeField(description='创建时间')
    update_time = UpdateTimeField(description="更新时间")

    async def save(self, *args, **kwargs):
        """确保时间字段正确设置"""
        # 对于新记录，确保创建时间已设置
        if not self._saved_in_db and self.create_time is None:
            self.create_time = datetime.now()

        # 确保更新时间总是设置
        self.update_time = datetime.now()

        await super().save(*args, **kwargs)

    class Meta:
        table = None
        abstract = True


class Role(TimestampMixin):
    user: fields.ManyToManyRelation["User"]
    role_name = fields.CharField(max_length=15, description="角色名称")
    access: fields.ManyToManyRelation["Access"] = \
        fields.ManyToManyField("base.Access", related_name="role", on_delete=fields.CASCADE)
    role_status = fields.BooleanField(default=False, description="True:启用 False:禁用")
    role_desc = fields.CharField(null=True, max_length=255, description='角色描述')

    class Meta:
        table_description = "角色表"
        table = "role"


class UserWechat(TimestampMixin):
    city = fields.CharField(null=True, max_length=255, description='城市')
    country = fields.CharField(null=True, max_length=255, description='国家')
    headimgurl = fields.CharField(null=True, max_length=255, description='微信头像')
    nickname = fields.CharField(null=True, max_length=255, description='微信昵称')
    openid = fields.CharField(unique=True, max_length=255, description='openid')
    unionid = fields.CharField(unique=True, null=True, max_length=255, description='unionid')
    province = fields.CharField(null=True, max_length=255, description='省份')
    sex = fields.IntField(null=True, description='性别')
    user: fields.OneToOneRelation["User"] = \
        fields.OneToOneField("base.User", related_name="wechat", on_delete=fields.CASCADE)

    class Meta:
        table_description = "用户微信"
        table = "user_wechat"



class User(TimestampMixin):
    role: fields.ManyToManyRelation["Role"] = \
        fields.ManyToManyField("base.Role", related_name="user", on_delete=fields.CASCADE)
    username = fields.CharField(null=True, max_length=20, description="用户名")
    user_type = fields.BooleanField(default=False, description="用户类型 True:超级管理员 False:普通管理员")
    password = fields.CharField(null=True, max_length=255)
    nickname = fields.CharField(default='binkuolo', max_length=255, description='昵称')
    user_phone = fields.CharField(null=True, description="手机号", max_length=11)
    user_email = fields.CharField(null=True, description='邮箱', max_length=255)
    full_name = fields.CharField(null=True, description='姓名', max_length=255)
    user_status = fields.IntField(default=0, description='0未激活 1正常 2禁用')
    header_img = fields.CharField(null=True, max_length=255, description='头像')
    sex = fields.IntField(default=0, null=True, description='0未知 1男 2女')
    remarks = fields.CharField(null=True, max_length=30, description="备注")
    client_host = fields.CharField(null=True, max_length=19, description="访问IP")
    wechat: fields.OneToOneRelation[UserWechat]

    class Meta:
        table_description = "用户表"
        table = "user"


class Access(TimestampMixin):
    role: fields.ManyToManyRelation[Role]
    access_name = fields.CharField(max_length=15, description="权限名称")
    parent_id = fields.IntField(default=0, description='父id')
    scopes = fields.CharField(unique=True, max_length=255, description='权限范围标识')
    access_desc = fields.CharField(null=True, max_length=255, description='权限描述')
    menu_icon = fields.CharField(null=True, max_length=255, description='菜单图标')
    is_check = fields.BooleanField(default=False, description='是否验证权限 True为验证 False不验证')
    is_menu = fields.BooleanField(default=False, description='是否为菜单 True菜单 False不是菜单')

    class Meta:
        table_description = "权限表"
        table = "access"


class AccessLog(TimestampMixin):
    user_id = fields.IntField(description="用户ID")
    target_url = fields.CharField(null=True, description="访问的url", max_length=255)
    user_agent = fields.CharField(null=True, description="访问UA", max_length=255)
    request_params = fields.JSONField(null=True, description="请求参数get|post")
    ip = fields.CharField(null=True, max_length=32, description="访问IP")
    note = fields.CharField(null=True, max_length=255, description="备注")

    class Meta:
        table_description = "用户操作记录表"
        table = "access_log"


class SystemParams(TimestampMixin):
    params_name = fields.CharField(unique=True, max_length=255, description="参数名")
    params = fields.JSONField(description="参数")

    class Meta:
        table_description = "系统参数表"
        table = "system_params"